﻿using System;
using System.Windows.Controls;

namespace FirstFloor.P2P
{
    /// <summary>
    /// Provides the basic functionality of a turn based game.
    /// </summary>
    public abstract class TurnBasedGame
    {
        private TurnBasedGameState gameState = TurnBasedGameState.Loaded;
        private TurnBasedGameResult gameResult = TurnBasedGameResult.None;
        private bool startedWithMyTurn = false;

        /// <summary>
        /// Initializes a new instance of the <see cref="TurnBasedGame"/> class.
        /// </summary>
        public TurnBasedGame()
        {
            P2PApplication.Current.StateChanged += P2PApplication_StateChanged;
        }

        private void P2PApplication_StateChanged(object sender, P2PApplicationStateEventArgs e)
        {
            if (e.State == P2PApplicationState.Connected) {
                this.gameState = TurnBasedGameState.Loaded;
                this.gameResult = TurnBasedGameResult.None;

                OnGameStateChanged(this.gameState, P2PApplicationCloseReason.None);
            }
            else if (e.State == P2PApplicationState.Closed) {
                this.gameResult = TurnBasedGameResult.None;

                if (this.gameState != TurnBasedGameState.Closed) {
                    this.gameState = TurnBasedGameState.Closed;

                    OnGameStateChanged(this.gameState, e.CloseReason);
                }
            }
        }

        /// <summary>
        /// Gets the state of the game.
        /// </summary>
        protected TurnBasedGameState GameState
        {
            get { return this.gameState; }
        }

        /// <summary>
        /// Gets the game result. Returns a useful value only when GameState is GameOver.
        /// </summary>
        protected TurnBasedGameResult GameResult
        {
            get { return this.gameResult; }
        }

        /// <summary>
        /// Gets the users.
        /// </summary>
        /// <value>The users.</value>
        protected P2PUserList Users
        {
            get { return P2PApplication.Current.Users; }
        }

        /// <summary>
        /// Connects this instance to the P2P network.
        /// </summary>
        protected void Connect()
        {
            P2PApplication.Current.Connect();
        }

        /// <summary>
        /// Gets a value indicating whether the current game was started with my turn.
        /// </summary>
        protected bool GameStartedWithMyTurn
        {
            get { return this.startedWithMyTurn; }
        }

        /// <summary>
        /// Starts the game and specify which user's turn is first.
        /// </summary>
        /// <param name="startMyTurn">if set to <c>true</c> [start my turn].</param>
        protected void StartGame(bool startMyTurn)
        {
            this.startedWithMyTurn = startMyTurn;
            this.gameState = TurnBasedGameState.StartingGame;
            this.gameResult = TurnBasedGameResult.None;

            OnGameStateChanged(this.gameState, P2PApplicationCloseReason.None);

            this.gameState = startMyTurn ? TurnBasedGameState.MyTurn : TurnBasedGameState.RemoteTurn;

            OnGameStateChanged(this.gameState, P2PApplicationCloseReason.None);
        }

        /// <summary>
        /// Stops the game and set the game result.
        /// </summary>
        /// <param name="result">The result.</param>
        protected void StopGame(TurnBasedGameResult result)
        {
            this.gameState = TurnBasedGameState.GameOver;
            this.gameResult = result;

            OnGameStateChanged(this.gameState, P2PApplicationCloseReason.None);
        }

        /// <summary>
        /// Switches the turn.
        /// </summary>
        protected void SwitchTurn()
        {
            if (this.gameState == TurnBasedGameState.MyTurn) {
                this.gameState = TurnBasedGameState.RemoteTurn;
            }
            else if (this.gameState == TurnBasedGameState.RemoteTurn) {
                this.gameState = TurnBasedGameState.MyTurn;
            }
            else {
                throw new InvalidOperationException("Unable to switch turn, game state must be MyTurn or RemoteTurn");
            }

            OnGameStateChanged(this.gameState, P2PApplicationCloseReason.None);
        }

        /// <summary>
        /// Sends the data.
        /// </summary>
        /// <param name="data">The data.</param>
        protected void SendData(string data)
        {
            P2PApplication.Current.SendData(data);
        }

        /// <summary>
        /// Occurs when the game state has changed.
        /// </summary>
        /// <param name="gameState">State of the game.</param>
        /// <param name="closeReason">The close reason.</param>
        protected abstract void OnGameStateChanged(TurnBasedGameState gameState, P2PApplicationCloseReason closeReason);
    }
}
